int inst_len);
asmlinkage void do_IRQ(struct cpu_user_regs *);
-static int svm_reset_to_realmode(struct vcpu *v,
- struct cpu_user_regs *regs);
+static int svm_reset_to_realmode(
+ struct vcpu *v, struct cpu_user_regs *regs);
+static void svm_update_guest_cr(struct vcpu *v, unsigned int cr);
/* va of hardware host save area */
static void *hsa[NR_CPUS] __read_mostly;
vmcb->rsp = c->rsp;
vmcb->rflags = c->rflags;
- v->arch.hvm_vcpu.guest_cr[0] = c->cr0;
- vmcb->cr0 = v->arch.hvm_vcpu.hw_cr[0] =
- c->cr0 | X86_CR0_WP | X86_CR0_ET | X86_CR0_PG;
+ v->arch.hvm_vcpu.guest_cr[0] = c->cr0 | X86_CR0_ET;
+ svm_update_guest_cr(v, 0);
v->arch.hvm_vcpu.guest_cr[2] = c->cr2;
+ svm_update_guest_cr(v, 2);
+ v->arch.hvm_vcpu.guest_cr[4] = c->cr4;
+ svm_update_guest_cr(v, 4);
+
#ifdef HVM_DEBUG_SUSPEND
printk("%s: cr3=0x%"PRIx64", cr0=0x%"PRIx64", cr4=0x%"PRIx64".\n",
- __func__,
- c->cr3,
- c->cr0,
- c->cr4);
+ __func__, c->cr3, c->cr0, c->cr4);
#endif
- if ( !hvm_paging_enabled(v) )
- {
- printk("%s: paging not enabled.\n", __func__);
- goto skip_cr3;
- }
-
- if ( c->cr3 == v->arch.hvm_vcpu.guest_cr[3] )
+ if ( hvm_paging_enabled(v) && !paging_mode_hap(v->domain) )
{
- /*
- * This is simple TLB flush, implying the guest has
- * removed some translation or changed page attributes.
- * We simply invalidate the shadow.
- */
- mfn = gmfn_to_mfn(v->domain, c->cr3 >> PAGE_SHIFT);
- if ( mfn != pagetable_get_pfn(v->arch.guest_table) )
- goto bad_cr3;
- }
- else
- {
- /*
- * If different, make a shadow. Check if the PDBR is valid
- * first.
- */
HVM_DBG_LOG(DBG_LEVEL_VMMU, "CR3 c->cr3 = %"PRIx64, c->cr3);
mfn = gmfn_to_mfn(v->domain, c->cr3 >> PAGE_SHIFT);
if( !mfn_valid(mfn) || !get_page(mfn_to_page(mfn), v->domain) )
goto bad_cr3;
-
old_base_mfn = pagetable_get_pfn(v->arch.guest_table);
v->arch.guest_table = pagetable_from_pfn(mfn);
if (old_base_mfn)
v->arch.hvm_vcpu.guest_cr[3] = c->cr3;
}
- skip_cr3:
- vmcb->cr4 = v->arch.hvm_vcpu.hw_cr[4] = c->cr4 | HVM_CR4_HOST_MASK;
- v->arch.hvm_vcpu.guest_cr[4] = c->cr4;
-
vmcb->idtr.limit = c->idtr_limit;
vmcb->idtr.base = c->idtr_base;
if ( paging_mode_hap(v->domain) )
{
- vmcb->cr0 = v->arch.hvm_vcpu.hw_cr[0] = v->arch.hvm_vcpu.guest_cr[0];
- vmcb->cr4 = v->arch.hvm_vcpu.hw_cr[4] =
- v->arch.hvm_vcpu.guest_cr[4] | (HVM_CR4_HOST_MASK & ~X86_CR4_PAE);
- vmcb->cr3 = v->arch.hvm_vcpu.hw_cr[3] = c->cr3;
vmcb->np_enable = 1;
vmcb->g_pat = 0x0007040600070406ULL; /* guest PAT */
vmcb->h_cr3 = pagetable_get_paddr(v->domain->arch.phys_table);
switch ( cr )
{
case 0:
- vmcb->cr0 = v->arch.hvm_vcpu.hw_cr[0];
+ vmcb->cr0 = v->arch.hvm_vcpu.guest_cr[0];
+ if ( !paging_mode_hap(v->domain) )
+ vmcb->cr0 |= X86_CR0_PG | X86_CR0_WP;
break;
case 2:
- vmcb->cr2 = v->arch.hvm_vcpu.hw_cr[2];
+ vmcb->cr2 = v->arch.hvm_vcpu.guest_cr[2];
break;
case 3:
vmcb->cr3 = v->arch.hvm_vcpu.hw_cr[3];
svm_asid_inv_asid(v);
break;
case 4:
- vmcb->cr4 = v->arch.hvm_vcpu.hw_cr[4];
+ vmcb->cr4 = HVM_CR4_HOST_MASK;
+ if ( paging_mode_hap(v->domain) )
+ vmcb->cr4 &= ~X86_CR4_PAE;
+ vmcb->cr4 |= v->arch.hvm_vcpu.guest_cr[4];
break;
default:
BUG();
if ( !(v->arch.hvm_vcpu.guest_cr[0] & X86_CR0_TS) )
{
v->arch.hvm_svm.vmcb->exception_intercepts |= 1U << TRAP_no_device;
- vmcb->cr0 = v->arch.hvm_vcpu.hw_cr[0] |= X86_CR0_TS;
+ vmcb->cr0 |= X86_CR0_TS;
}
}
vmcb->exception_intercepts &= ~(1U << TRAP_no_device);
if ( !(v->arch.hvm_vcpu.guest_cr[0] & X86_CR0_TS) )
- vmcb->cr0 = v->arch.hvm_vcpu.hw_cr[0] &= ~X86_CR0_TS;
+ vmcb->cr0 &= ~X86_CR0_TS;
}
/* Reserved bits ECX: [31:14], [12:4], [2:1]*/
/* TS being cleared means that it's time to restore fpu state. */
setup_fpu(current);
vmcb->exception_intercepts &= ~(1U << TRAP_no_device);
- vmcb->cr0 = v->arch.hvm_vcpu.hw_cr[0] &= ~X86_CR0_TS; /* clear TS */
+ vmcb->cr0 &= ~X86_CR0_TS; /* clear TS */
v->arch.hvm_vcpu.guest_cr[0] &= ~X86_CR0_TS; /* clear TS */
break;
memset(regs, 0, sizeof(struct cpu_user_regs));
- vmcb->cr0 = v->arch.hvm_vcpu.hw_cr[0] =
- X86_CR0_ET | X86_CR0_PG | X86_CR0_WP;
v->arch.hvm_vcpu.guest_cr[0] = X86_CR0_ET;
+ svm_update_guest_cr(v, 0);
- vmcb->cr2 = 0;
- vmcb->efer = EFER_SVME;
+ v->arch.hvm_vcpu.guest_cr[2] = 0;
+ svm_update_guest_cr(v, 2);
- vmcb->cr4 = v->arch.hvm_vcpu.hw_cr[4] = HVM_CR4_HOST_MASK;
v->arch.hvm_vcpu.guest_cr[4] = 0;
+ svm_update_guest_cr(v, 4);
- if ( paging_mode_hap(v->domain) )
- {
- vmcb->cr0 = v->arch.hvm_vcpu.hw_cr[0] = v->arch.hvm_vcpu.guest_cr[0];
- vmcb->cr4 = v->arch.hvm_vcpu.hw_cr[4] =
- v->arch.hvm_vcpu.guest_cr[4] | (HVM_CR4_HOST_MASK & ~X86_CR4_PAE);
- }
+ vmcb->efer = EFER_SVME;
/* This will jump to ROMBIOS */
vmcb->rip = 0xFFF0;
unsigned long va;
va = vmcb->exitinfo2;
regs->error_code = vmcb->exitinfo1;
- HVM_DBG_LOG(DBG_LEVEL_VMMU,
+ HVM_DBG_LOG(DBG_LEVEL_VMMU,
"eax=%lx, ebx=%lx, ecx=%lx, edx=%lx, esi=%lx, edi=%lx",
(unsigned long)regs->eax, (unsigned long)regs->ebx,
(unsigned long)regs->ecx, (unsigned long)regs->edx,
vmcb->tr.base = 0;
vmcb->tr.limit = 0xff;
- /* Guest CR0. */
- vmcb->cr0 = v->arch.hvm_vcpu.hw_cr[0] = read_cr0();
- v->arch.hvm_vcpu.guest_cr[0] =
- v->arch.hvm_vcpu.hw_cr[0] & ~(X86_CR0_PG | X86_CR0_TS);
+ v->arch.hvm_vcpu.guest_cr[0] = X86_CR0_PE | X86_CR0_TS;
+ hvm_update_guest_cr(v, 0);
- /* Guest CR4. */
- v->arch.hvm_vcpu.guest_cr[4] =
- read_cr4() & ~(X86_CR4_PGE | X86_CR4_PSE | X86_CR4_PAE);
- vmcb->cr4 = v->arch.hvm_vcpu.hw_cr[4] =
- v->arch.hvm_vcpu.guest_cr[4] | HVM_CR4_HOST_MASK;
+ v->arch.hvm_vcpu.guest_cr[4] = 0;
+ hvm_update_guest_cr(v, 4);
paging_update_paging_modes(v);
- vmcb->cr3 = v->arch.hvm_vcpu.hw_cr[3];
if ( paging_mode_hap(v->domain) )
{
- vmcb->cr0 = v->arch.hvm_vcpu.hw_cr[0] = v->arch.hvm_vcpu.guest_cr[0];
vmcb->np_enable = 1; /* enable nested paging */
vmcb->g_pat = 0x0007040600070406ULL; /* guest PAT */
vmcb->h_cr3 = pagetable_get_paddr(v->domain->arch.phys_table);
- vmcb->cr4 = v->arch.hvm_vcpu.hw_cr[4] = v->arch.hvm_vcpu.guest_cr[4] =
- HVM_CR4_HOST_MASK & ~X86_CR4_PAE;
vmcb->exception_intercepts = HVM_TRAP_MASK;
/* No point in intercepting CR3/4 reads, because the hardware
local_irq_restore(flags);
}
+struct foreign_vmcs {
+ struct vcpu *v;
+ unsigned int count;
+};
+static DEFINE_PER_CPU(struct foreign_vmcs, foreign_vmcs);
+
void vmx_vmcs_enter(struct vcpu *v)
{
+ struct foreign_vmcs *fv;
+
/*
* NB. We must *always* run an HVM VCPU on its own VMCS, except for
* vmx_vmcs_enter/exit critical regions.
*/
- if ( v == current )
+ if ( likely(v == current) )
return;
- vcpu_pause(v);
- spin_lock(&v->arch.hvm_vmx.vmcs_lock);
+ fv = &this_cpu(foreign_vmcs);
- vmx_clear_vmcs(v);
- vmx_load_vmcs(v);
+ if ( fv->v == v )
+ {
+ BUG_ON(fv->count == 0);
+ }
+ else
+ {
+ BUG_ON(fv->v != NULL);
+ BUG_ON(fv->count != 0);
+
+ vcpu_pause(v);
+ spin_lock(&v->arch.hvm_vmx.vmcs_lock);
+
+ vmx_clear_vmcs(v);
+ vmx_load_vmcs(v);
+
+ fv->v = v;
+ }
+
+ fv->count++;
}
void vmx_vmcs_exit(struct vcpu *v)
{
- if ( v == current )
+ struct foreign_vmcs *fv;
+
+ if ( likely(v == current) )
return;
- /* Don't confuse vmx_do_resume (for @v or @current!) */
- vmx_clear_vmcs(v);
- if ( is_hvm_vcpu(current) )
- vmx_load_vmcs(current);
+ fv = &this_cpu(foreign_vmcs);
+ BUG_ON(fv->v != v);
+ BUG_ON(fv->count == 0);
+
+ if ( --fv->count == 0 )
+ {
+ /* Don't confuse vmx_do_resume (for @v or @current!) */
+ vmx_clear_vmcs(v);
+ if ( is_hvm_vcpu(current) )
+ vmx_load_vmcs(current);
+
+ spin_unlock(&v->arch.hvm_vmx.vmcs_lock);
+ vcpu_unpause(v);
- spin_unlock(&v->arch.hvm_vmx.vmcs_lock);
- vcpu_unpause(v);
+ fv->v = NULL;
+ }
}
struct xgt_desc {
static void construct_vmcs(struct vcpu *v)
{
- unsigned long cr0, cr4;
union vmcs_arbytes arbytes;
vmx_vmcs_enter(v);
__vmwrite(EXCEPTION_BITMAP, HVM_TRAP_MASK | (1U << TRAP_page_fault));
- /* Guest CR0. */
- cr0 = read_cr0();
- v->arch.hvm_vcpu.hw_cr[0] = cr0;
- __vmwrite(GUEST_CR0, v->arch.hvm_vcpu.hw_cr[0]);
- v->arch.hvm_vcpu.guest_cr[0] = cr0 & ~(X86_CR0_PG | X86_CR0_TS);
- __vmwrite(CR0_READ_SHADOW, v->arch.hvm_vcpu.guest_cr[0]);
-
- /* Guest CR4. */
- cr4 = read_cr4();
- __vmwrite(GUEST_CR4, cr4 & ~X86_CR4_PSE);
- v->arch.hvm_vcpu.guest_cr[4] =
- cr4 & ~(X86_CR4_PGE | X86_CR4_VMXE | X86_CR4_PAE);
- __vmwrite(CR4_READ_SHADOW, v->arch.hvm_vcpu.guest_cr[4]);
+ v->arch.hvm_vcpu.guest_cr[0] = X86_CR0_PE | X86_CR0_ET;
+ hvm_update_guest_cr(v, 0);
+
+ v->arch.hvm_vcpu.guest_cr[4] = 0;
+ hvm_update_guest_cr(v, 4);
if ( cpu_has_vmx_tpr_shadow )
{